package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"os"

	"github.com/openzipkin/zipkin-go"
	zipkinhttp "github.com/openzipkin/zipkin-go/middleware/http"
	"github.com/openzipkin/zipkin-go/model"
	"github.com/openzipkin/zipkin-go/reporter"
)

var datakitURL, datakitPort, datakitURLPath, hostPort string

func main() {
	datakitURL = os.Getenv("DATAKIT_HOST")
	datakitPort = os.Getenv("DATAKIT_PORT")
	datakitURLPath = os.Getenv("DATAKIT_URL_PATH")

	if len(datakitURL) == 0 {
		fmt.Println("datakit URL is empty")
		return
	}

	if len(datakitPort) == 0 {
		fmt.Println("datakit port is empty")
		return
	}

	if len(datakitURLPath) == 0 {
		fmt.Println("datakit URL path is empty")
		return
	}

	hostPort = net.JoinHostPort(datakitURL, datakitPort)
	hostPort += datakitURLPath
	fmt.Println("host = " + hostPort)

	apiReq(hostPort)
}

func apiReq(hostPort string) {
	reporter := NewDKReporter("http://" + hostPort)

	// create our local service endpoint
	endpoint, err := zipkin.NewEndpoint("myService", "localhost:0")
	if err != nil {
		log.Fatalf("unable to create local endpoint: %+v\n", err)
	}

	// initialize our tracer
	tracer, err := zipkin.NewTracer(reporter, zipkin.WithLocalEndpoint(endpoint))
	if err != nil {
		log.Fatalf("unable to create tracer: %+v\n", err)
	}

	// create global zipkin traced http client
	client, err := zipkinhttp.NewClient(tracer, zipkinhttp.ClientTrace(true))
	if err != nil {
		log.Fatalf("unable to create client: %+v\n", err)
	}

	pathReq(client, "http://www.baidu.com/", "baidu_test")
}

func pathReq(client *zipkinhttp.Client, uRL, name string) {

	// initiate a call to some_func
	var req *http.Request
	req, err := http.NewRequest("GET", uRL, nil)
	if err != nil {
		log.Fatalf("unable to create http request: %+v\n", err)
	}

	var res *http.Response
	res, err = client.DoWithAppSpan(req, name)
	if err != nil {
		log.Fatalf("unable to do http request: %+v\n", err)
	}
	_ = res.Body.Close()
}

// dkReporter will send spans to Datakit.
type dkReporter struct {
	postURL string
}

// NewDKReporter returns a new dkReporter.
func NewDKReporter(postURL string) reporter.Reporter {
	return &dkReporter{
		postURL: postURL,
	}
}

// Send outputs a span to the Datakit.
func (r *dkReporter) Send(s model.SpanModel) {
	// b, err := json.MarshalIndent(s, "", "  ")
	s1 := []model.SpanModel{s}
	b, err := json.Marshal(s1)
	if err != nil {
		fmt.Printf("json.MarshalIndent failed: %v \n", err)
		return
	}

	req, err := http.NewRequest("POST", r.postURL, bytes.NewReader((b)))
	if err != nil {
		fmt.Printf("http.NewRequest failed: %v \n", err)
		return
	}

	req.Header.Add("Content-Type", "application/json")

	////////////////////////////////////////////////////////////////////////////

	bys, err := httputil.DumpRequest(req, true)
	if err != nil {
		fmt.Printf("httputil.DumpRequest failed: %v \n", err)
		return
	}
	fmt.Println(string(bys))

	////////////////////////////////////////////////////////////////////////////

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		fmt.Printf("client.Do failed: %v \n", err)
		return
	}

	defer resp.Body.Close()

	fmt.Printf("status code = %d\n", resp.StatusCode)

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("ioutil.ReadAll failed: %v \n", err)
		return
	}
	fmt.Printf("resp = %s\n", string(respBody))
}

// Close closes the reporter
func (*dkReporter) Close() error { return nil }
